﻿#region Using Directives

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    using Csla;
    using Csla.Data;
    using Csla.Reflection;
    using Csla.Server;

    using MarketPulse.BusinessLogic.Common;
    using MarketPulse.BusinessLogic.Common.Criteria;
    using Private = MarketPulse.BusinessLogic.Private;
    using MarketPulse.BusinessLogic.Private.Criteria;

    using MarketPulse.DataAccess.DataContextObjects.Production;

#endregion

namespace MarketPulse.DataAccess.Factory
{
    /// <summary>
    /// Abstracts the data access for a Visit, VisitList, VisitInfo and VisitInfoList away from a Visit Business Object.
    /// </summary>
    public class VisitFactory : ObjectFactory
    {
        #region Member Variables

            /// <summary>
            /// Property that stores the name of the class.
            /// </summary>
            private static readonly Type mClass = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType;

            /// <summary>
            /// Property that stores the log4net logger for this class.
            /// </summary>
            private static readonly log4net.ILog mLog = log4net.LogManager.GetLogger(mClass);

        #endregion

        #region Methods

            #region Create Methods

                #region VisitEvent

                    /// <summary>
                    /// Method used to create and return a new VisitEvent object instance
                    /// </summary>
                    /// <returns>The newly created VisitEvent object</returns>
                    public Private.VisitEvent CreateEvent()
                    {
                        // Create a new instance of the object
                        var visitEvent = (Private.VisitEvent)MethodCaller.CreateInstance(typeof(Private.VisitEvent));

                        // Mark it as a new object
                        MarkNew(visitEvent);
                        CheckRules(visitEvent);

                        MarkAsChild(visitEvent);

                        return visitEvent;
                    }

                #endregion

            #endregion

            #region Fetch Methods

                #region VisitInfo

                    /// <summary>
                    /// Method used to retrieve an existing Visit from the database based on the Guid supplied
                    /// </summary>
                    /// <param name="criteria">The criteria object holding the Guid of the Visit to retrieve</param>
                    /// <returns>The Visit object retrieved from the database</returns>
                    public VisitInfo FetchInfo(SingleCriteria<Guid> criteria)
                    {
                        try
                        {
                            using (var manager = ContextManager<MUM_dev>.GetManager(Database.BusinessSystem))
                            {
                                // Create an instance to return
                                var visitInfo = (VisitInfo)MethodCaller.CreateInstance(typeof(VisitInfo));

                                // Fetch the data from the database based on the criteria
                                var selectResult = manager.DataContext.UspVisitSelect(criteria.Value, null);

                                // Get the result
                                UspVisitSelectResult result = null;
                                try
                                {
                                    result = selectResult.Single();
                                }
                                catch (InvalidOperationException ioe)
                                {
                                    // Construct error message
                                    StringBuilder errorMessage = new StringBuilder();
                                    errorMessage.Append("Unable to locate exactly one Visit with Guid = [ ");
                                    errorMessage.Append(criteria.Value);
                                    errorMessage.Append(" ]");
                                    mLog.Error(errorMessage.ToString(), ioe);
                                    throw new DataAccessException(errorMessage.ToString());
                                }

                                // Common properties inherited from MarketPulseBase<VisitInfo>
                                LoadProperty(visitInfo, VisitInfo.GUIDProperty, result.VisitGUID);
                                LoadProperty(visitInfo, VisitInfo.ObsoleteProperty, result.Obsolete.Value);
                                LoadProperty(visitInfo, VisitInfo.InsertDateTimeProperty, result.InsertDateTime.Value);
                                LoadProperty(visitInfo, VisitInfo.InsertUserGUIDProperty, result.InsertUserGUID.Value);
                                LoadProperty(visitInfo, VisitInfo.UpdateDateTimeProperty, result.UpdateDateTime.Value);
                                LoadProperty(visitInfo, VisitInfo.UpdateUserGUIDProperty, result.UpdateUserGUID.Value);
                                // Other properties                    
                                LoadProperty(visitInfo, VisitInfo.UserGUIDProperty, result.UserGUID);
                                LoadProperty(visitInfo, VisitInfo.RoundGUIDProperty, result.RoundGUID);
                                LoadProperty(visitInfo, VisitInfo.BranchGUIDProperty, result.BranchGUID);
                                LoadProperty(visitInfo, VisitInfo.ResponseGUIDProperty, result.ResponseGUID);
                                LoadProperty(visitInfo, VisitInfo.SurveyGUIDProperty, result.SurveyGUID);
                                LoadProperty(visitInfo, VisitInfo.VisitStatusTypeGUIDProperty, result.VisitStatusTypeGUID);
                                LoadProperty(visitInfo, VisitInfo.ValidStartDateTimeProperty, result.ValidStartDateTime);
                                LoadProperty(visitInfo, VisitInfo.ValidEndDateTimeProperty, result.ValidEndDateTime);
                                LoadProperty(visitInfo, VisitInfo.PlannedDateTimeProperty, result.PlannedDateTime);
                                LoadProperty(visitInfo, VisitInfo.ActualStartDateTimeProperty, result.ActualStartDateTime);
                                LoadProperty(visitInfo, VisitInfo.ActualEndDateTimeProperty, result.ActualEndDateTime);

                                LoadProperty(visitInfo, VisitInfo.VisitLabelProperty, result.VisitLabel);

                                // Set the survey version ID if it has a value
                                if (result.SurveyVersionID.HasValue)
                                {
                                    LoadProperty(visitInfo, VisitInfo.SurveyVersionIDProperty, result.SurveyVersionID.Value);
                                }
                                // Make sure that CSLA knows this has changed since being instantiated
                                MarkOld(visitInfo);

                                return visitInfo;
                            }
                        }
                        catch (DataAccessException dae)
                        {
                            mLog.Error(dae.ToString());
                            throw dae;
                        }
                        catch (Exception ex)
                        {
                            mLog.Error(ex.ToString());
                            throw ex;
                        }
                    }

                #endregion

                #region Visit

                    /// <summary>
                    /// Method used to retrieve an existing Visit from the database based on the Guid supplied
                    /// </summary>
                    /// <param name="criteria">The criteria object holding the Guid of the Visit to retrieve</param>
                    /// <returns>The Visit object retrieved from the database</returns>
                    public Private.Visit Fetch(VisitGUIDCriteria criteria)
                    {
                        try
                        {
                            using (var manager = ContextManager<MUM_dev>.GetManager(Database.BusinessSystem))
                            {
                                // Create an instance to return
                                var visit = (Private.Visit)MethodCaller.CreateInstance(typeof(Private.Visit));

                                // Fetch the data from the database based on the criteria
                                var selectResult = manager.DataContext.UspVisitSelect(criteria.VisitGUID, null);

                                // Get the result
                                UspVisitSelectResult result = null;
                                try
                                {
                                    result = selectResult.Single();
                                }
                                catch (InvalidOperationException ioe)
                                {
                                    // Construct error message
                                    StringBuilder errorMessage = new StringBuilder();
                                    errorMessage.Append("Unable to locate exactly one Visit with Guid = [ ");
                                    errorMessage.Append(criteria.VisitGUID);
                                    errorMessage.Append(" ]");
                                    mLog.Error(errorMessage.ToString(), ioe);
                                    throw new DataAccessException(errorMessage.ToString());
                                }

                                // Common properties inherited from MarketPulseBase<Visit>
                                LoadProperty(visit, Private.Visit.GUIDProperty, criteria.VisitGUID);
                                LoadProperty(visit, Private.Visit.VersionIDProperty, result.VisitVersionID.Value);
                                LoadProperty(visit, Private.Visit.ObsoleteProperty, result.Obsolete.Value);
                                LoadProperty(visit, Private.Visit.InsertDateTimeProperty, result.InsertDateTime.Value);
                                LoadProperty(visit, Private.Visit.InsertUserGUIDProperty, result.InsertUserGUID.Value);
                                LoadProperty(visit, Private.Visit.UpdateDateTimeProperty, result.UpdateDateTime.Value);
                                LoadProperty(visit, Private.Visit.UpdateUserGUIDProperty, result.UpdateUserGUID.Value);
                                // Other properties                    
                                LoadProperty(visit, Private.Visit.UserGUIDProperty, result.UserGUID);
                                LoadProperty(visit, Private.Visit.RoundGUIDProperty, result.RoundGUID);
                                LoadProperty(visit, Private.Visit.BranchGUIDProperty, result.BranchGUID);
                                LoadProperty(visit, Private.Visit.ResponseGUIDProperty, result.ResponseGUID);
                                LoadProperty(visit, Private.Visit.SurveyGUIDProperty, result.SurveyGUID);
                                LoadProperty(visit, Private.Visit.VisitStatusTypeGUIDProperty, result.VisitStatusTypeGUID);
                                LoadProperty(visit, Private.Visit.ValidStartDateTimeProperty, result.ValidStartDateTime);
                                LoadProperty(visit, Private.Visit.ValidEndDateTimeProperty, result.ValidEndDateTime);
                                LoadProperty(visit, Private.Visit.PlannedDateTimeProperty, result.PlannedDateTime);
                                LoadProperty(visit, Private.Visit.ActualStartDateTimeProperty, result.ActualStartDateTime);
                                LoadProperty(visit, Private.Visit.ActualEndDateTimeProperty, result.ActualEndDateTime);
                                LoadProperty(visit, Private.Visit.VisitLabelProperty, result.VisitLabel);

                                int dataEntryLag = Convert.ToInt32(result.DataEntryPeriod.Value);

                                LoadProperty(visit, Private.Visit.DataEntryLagProperty, new TimeSpan(dataEntryLag, 0, 0));

                                // Set the survey version ID if it has a value
                                if (result.SurveyVersionID.HasValue)
                                {
                                    LoadProperty(visit, Private.Visit.SurveyVersionIDProperty, result.SurveyVersionID.Value);
                                }
                                // Make sure that CSLA knows this has changed since being instantiated
                                MarkOld(visit);

                                return visit;
                            }
                        }
                        catch (DataAccessException dae)
                        {
                            mLog.Error(dae.ToString());
                            throw dae;
                        }
                        catch (Exception ex)
                        {
                            mLog.Error(ex.ToString());
                            throw ex;
                        }
                    }

                #endregion

                #region VisitInfoList

                    /// <summary>
                    /// Method used to fetch a read only list of read only Visit objects from the database based on the criteria supplied
                    /// </summary>
                    /// <param name="criteria">The criteria object holding the values used to retrieve the list</param>
                    /// <returns>A read only list of read only Visit objects retrieved from the database</returns>
                    public VisitInfoList FetchInfoList(UserGUIDCriteria criteria)
                    {
                        try
                        {
                            using (var manager = ContextManager<MUM_dev>.GetManager(Database.BusinessSystem))
                            {
                                // Create an instance to return
                                var visitInfoList = (VisitInfoList)MethodCaller.CreateInstance(typeof(VisitInfoList));

                                // Fetch the data from the database based on the criteria
                                var selectResult = manager.DataContext.UspVisitSearch(null, null, criteria.UserGUID);

                                // VisitInfoList is a read-only collection,
                                // so typically, when the data access is implemented in
                                // DataPortal_Fetch within the business object, the
                                // private IsReadOnly property must be set false in order to 
                                // populate the collection.  Here, within a factory 
                                // , it isn't visible so one must resort to calling the 
                                // SetIsReadOnly method provided by our parent, ObjectFactory.
                                SetIsReadOnly(visitInfoList, false);
                                foreach (UspVisitSearchResult result in selectResult)
                                {
                                    VisitInfo visitInfo = (VisitInfo)MethodCaller.CreateInstance(typeof(VisitInfo));

                                    // Common properties inherited from MarketPulseBase<VisitInfo>
                                    LoadProperty(visitInfo, VisitInfo.GUIDProperty, result.VisitGUID);
                                    LoadProperty(visitInfo, VisitInfo.ObsoleteProperty, result.Obsolete.Value);
                                    LoadProperty(visitInfo, VisitInfo.InsertDateTimeProperty, result.InsertDateTime.Value);
                                    LoadProperty(visitInfo, VisitInfo.InsertUserGUIDProperty, result.InsertUserGUID.Value);
                                    LoadProperty(visitInfo, VisitInfo.UpdateDateTimeProperty, result.UpdateDateTime.Value);
                                    LoadProperty(visitInfo, VisitInfo.UpdateUserGUIDProperty, result.UpdateUserGUID.Value);
                                    // Other properties                    
                                    LoadProperty(visitInfo, VisitInfo.UserGUIDProperty, result.UserGUID);
                                    LoadProperty(visitInfo, VisitInfo.RoundGUIDProperty, result.RoundGUID);
                                    LoadProperty(visitInfo, VisitInfo.BranchGUIDProperty, result.BranchGUID);
                                    LoadProperty(visitInfo, VisitInfo.ResponseGUIDProperty, result.ResponseGUID);
                                    LoadProperty(visitInfo, VisitInfo.SurveyGUIDProperty, result.SurveyGUID);
                                    LoadProperty(visitInfo, VisitInfo.VisitStatusTypeGUIDProperty, result.VisitStatusTypeGUID);
                                    LoadProperty(visitInfo, VisitInfo.ValidStartDateTimeProperty, result.ValidStartDateTime);
                                    LoadProperty(visitInfo, VisitInfo.ValidEndDateTimeProperty, result.ValidEndDateTime);
                                    LoadProperty(visitInfo, VisitInfo.PlannedDateTimeProperty, result.PlannedDateTime);
                                    LoadProperty(visitInfo, VisitInfo.ActualStartDateTimeProperty, result.ActualStartDateTime);
                                    LoadProperty(visitInfo, VisitInfo.ActualEndDateTimeProperty, result.ActualEndDateTime);

                                    LoadProperty(visitInfo, VisitInfo.VisitLabelProperty, result.VisitLabel);

                                    // Set the survey version ID if it has a value
                                    if (result.SurveyVersionID.HasValue)
                                    {
                                        LoadProperty(visitInfo, VisitInfo.SurveyVersionIDProperty, result.SurveyVersionID.Value);
                                    }

                                    //CheckRules(visitInfo);

                                    // Make sure that CSLA knows this has changed since being instantiated
                                    MarkOld(visitInfo);

                                    // Add the item to the list
                                    visitInfoList.Add(visitInfo);
                                }
                                SetIsReadOnly(visitInfoList, true);

                                // Make sure that CSLA knows this has changed since being instantiated
                                MarkOld(visitInfoList);

                                return visitInfoList;
                            }
                        }
                        catch (InvalidOperationException ioe)
                        {
                            mLog.Error(ioe.ToString());
                            throw ioe;
                        }
                        catch (Exception ex)
                        {
                            mLog.Error(ex.ToString());
                            throw ex;
                        }
                    }

                    /// <summary>
                    /// Method used to fetch a read only list of read only Visit objects from the database based on the criteria supplied
                    /// </summary>
                    /// <param name="criteria">The criteria object holding the ProfileGUID, CompanyGUID and date range used to retrieve the list</param>
                    /// <returns>A read only list of read only Visit objects retrieved from the database</returns>
                    public VisitInfoList FetchInfoList(ClientGUIDAndProfileGUIDAndDateRangeCriteria criteria)
                    {
                        try
                        {
                            using (var manager = ContextManager<MUM_dev>.GetManager(Database.BusinessSystem))
                            {
                                // Create an instance to return
                                var visitInfoList = (VisitInfoList)MethodCaller.CreateInstance(typeof(VisitInfoList));

                                // Fetch the data from the database based on the criteria
                                var selectResult = manager.DataContext.UspVisitSelectByClientGUIDAndProfileGUIDAndDateRange(criteria.ClientGUID, criteria.ProfileGUID, criteria.StartDateTime, criteria.EndDateTime, true);

                                // VisitInfoList is a read-only collection,
                                // so typically, when the data access is implemented in
                                // DataPortal_Fetch within the business object, the
                                // private IsReadOnly property must be set false in order to 
                                // populate the collection.  Here, within a factory 
                                // , it isn't visible so one must resort to calling the 
                                // SetIsReadOnly method provided by our parent, ObjectFactory.
                                SetIsReadOnly(visitInfoList, false);
                                foreach (UspVisitSelectByClientGUIDAndProfileGUIDAndDateRangeResult result in selectResult)
                                {
                                    VisitInfo visitInfo = (VisitInfo)MethodCaller.CreateInstance(typeof(VisitInfo));

                                    // Common properties inherited from MarketPulseBase<VisitInfo>
                                    LoadProperty(visitInfo, VisitInfo.GUIDProperty, result.VisitGUID);
                                    LoadProperty(visitInfo, VisitInfo.ObsoleteProperty, result.Obsolete.Value);
                                    LoadProperty(visitInfo, VisitInfo.InsertDateTimeProperty, result.InsertDateTime.Value);
                                    LoadProperty(visitInfo, VisitInfo.InsertUserGUIDProperty, result.InsertUserGUID.Value);
                                    LoadProperty(visitInfo, VisitInfo.UpdateDateTimeProperty, result.UpdateDateTime.Value);
                                    LoadProperty(visitInfo, VisitInfo.UpdateUserGUIDProperty, result.UpdateUserGUID.Value);
                                    // Other properties                    
                                    LoadProperty(visitInfo, VisitInfo.UserGUIDProperty, result.UserGUID);
                                    LoadProperty(visitInfo, VisitInfo.RoundGUIDProperty, result.RoundGUID);
                                    LoadProperty(visitInfo, VisitInfo.BranchGUIDProperty, result.BranchGUID);
                                    LoadProperty(visitInfo, VisitInfo.ResponseGUIDProperty, result.ResponseGUID);
                                    LoadProperty(visitInfo, VisitInfo.SurveyGUIDProperty, result.SurveyGUID);
                                    LoadProperty(visitInfo, VisitInfo.VisitStatusTypeGUIDProperty, result.VisitStatusTypeGUID);
                                    LoadProperty(visitInfo, VisitInfo.ValidStartDateTimeProperty, result.ValidStartDateTime);
                                    LoadProperty(visitInfo, VisitInfo.ValidEndDateTimeProperty, result.ValidEndDateTime);
                                    LoadProperty(visitInfo, VisitInfo.PlannedDateTimeProperty, result.PlannedDateTime);
                                    LoadProperty(visitInfo, VisitInfo.ActualStartDateTimeProperty, result.ActualStartDateTime);
                                    LoadProperty(visitInfo, VisitInfo.ActualEndDateTimeProperty, result.ActualEndDateTime);

                                    LoadProperty(visitInfo, VisitInfo.VisitLabelProperty, result.VisitLabel);

                                    // Set the survey version ID if it has a value
                                    if (result.SurveyVersionID.HasValue)
                                    {
                                        LoadProperty(visitInfo, VisitInfo.SurveyVersionIDProperty, result.SurveyVersionID.Value);
                                    }

                                    //CheckRules(visitInfo);

                                    // Make sure that CSLA knows this has changed since being instantiated
                                    MarkOld(visitInfo);

                                    // Add the item to the list
                                    visitInfoList.Add(visitInfo);
                                }
                                SetIsReadOnly(visitInfoList, true);

                                // Make sure that CSLA knows this has changed since being instantiated
                                MarkOld(visitInfoList);

                                return visitInfoList;
                            }
                        }
                        catch (InvalidOperationException ioe)
                        {
                            mLog.Error(ioe.ToString());
                            throw ioe;
                        }
                        catch (Exception ex)
                        {
                            mLog.Error(ex.ToString());
                            throw ex;
                        }
                    }

                #endregion

                #region VisitList

                    /// <summary>
                    /// Method used to fetch a list of Visit objects from the database based on the criteria supplied             
                    /// </summary>
                    /// <param name="criteria">The criteria object holding the values used to retrieve the list</param>
                    /// <returns>A populated list of Visit objects retrieved from the database</returns>
                    public Private.VisitList FetchList(UserGUIDCriteria criteria)
                    {
                        try
                        {
                            using (var manager = ContextManager<MUM_dev>.GetManager(Database.BusinessSystem))
                            {
                                // Create an instance to return
                                var visitList = (Private.VisitList)MethodCaller.CreateInstance(typeof(Private.VisitList));

                                // Fetch the data from the database based on the criteria
                                var selectResult = manager.DataContext.UspVisitSearch(null, null, criteria.UserGUID);

                                foreach (UspVisitSearchResult result in selectResult)
                                {
                                    Private.Visit visit = (Private.Visit)MethodCaller.CreateInstance(typeof(Private.Visit));

                                    // Common properties inherited from MarketPulseBase<VisitInfo>
                                    LoadProperty(visit, Private.Visit.GUIDProperty, result.VisitGUID);
                                    LoadProperty(visit, Private.Visit.ObsoleteProperty, result.Obsolete.Value);
                                    LoadProperty(visit, Private.Visit.InsertDateTimeProperty, result.InsertDateTime.Value);
                                    LoadProperty(visit, Private.Visit.InsertUserGUIDProperty, result.InsertUserGUID.Value);
                                    LoadProperty(visit, Private.Visit.UpdateDateTimeProperty, result.UpdateDateTime.Value);
                                    LoadProperty(visit, Private.Visit.UpdateUserGUIDProperty, result.UpdateUserGUID.Value);
                                    // Other properties
                                    LoadProperty(visit, Private.Visit.UserGUIDProperty, result.UserGUID);
                                    LoadProperty(visit, Private.Visit.RoundGUIDProperty, result.RoundGUID);
                                    LoadProperty(visit, Private.Visit.BranchGUIDProperty, result.BranchGUID);
                                    LoadProperty(visit, Private.Visit.ResponseGUIDProperty, result.ResponseGUID);
                                    LoadProperty(visit, Private.Visit.SurveyGUIDProperty, result.SurveyGUID);
                                    LoadProperty(visit, Private.Visit.VisitStatusTypeGUIDProperty, result.VisitStatusTypeGUID);
                                    LoadProperty(visit, Private.Visit.ValidStartDateTimeProperty, result.ValidStartDateTime);
                                    LoadProperty(visit, Private.Visit.ValidEndDateTimeProperty, result.ValidEndDateTime);
                                    LoadProperty(visit, Private.Visit.PlannedDateTimeProperty, result.PlannedDateTime);
                                    LoadProperty(visit, Private.Visit.ActualStartDateTimeProperty, result.ActualStartDateTime);
                                    LoadProperty(visit, Private.Visit.ActualEndDateTimeProperty, result.ActualEndDateTime);

                                    LoadProperty(visit, Private.Visit.VisitLabelProperty, result.VisitLabel);

                                    // Set the survey version ID if it has a value
                                    if (result.SurveyVersionID.HasValue)
                                    {
                                        LoadProperty(visit, Private.Visit.SurveyVersionIDProperty, result.SurveyVersionID.Value);
                                    }

                                    //CheckRules(visitInfo);

                                    // Make sure that CSLA knows this has changed since being instantiated
                                    MarkOld(visit);

                                    MarkAsChild(visit);

                                    // Add the item to the list
                                    visitList.Add(visit);
                                }

                                // Make sure that CSLA knows this has changed since being instantiated
                                MarkOld(visitList);

                                return visitList;
                            }
                        }
                        catch (InvalidOperationException ioe)
                        {
                            mLog.Error(ioe.ToString());
                            throw ioe;
                        }
                        catch (Exception ex)
                        {
                            mLog.Error(ex.ToString());
                            throw ex;
                        }
                    }

                #endregion

                #region VisitEventList

                    /// <summary>
                    /// Method used to fetch a list of VisitEvents associated with this Visit from 
                    /// the database given a the Visit GUID
                    /// </summary>
                    /// <param name="criteria">The criteria object holding the Guid of the Visit to retrieve the list for</param>
                    /// <returns>The collection of VisitEvents fetched from the database</returns>
                    public Private.VisitEventList FetchVisitEventList(SingleCriteria<Guid> criteria)
                    {
                        try
                        {
                            using (var manager = ContextManager<MUM_dev>.GetManager(Database.BusinessSystem))
                            {
                                var eventList = (Private.VisitEventList)MethodCaller.CreateInstance(typeof(Private.VisitEventList));

                                var selectResult = manager.DataContext.UspVisitEventSelectByVisitGUID(criteria.Value);

                                eventList.RaiseListChangedEvents = false;
                                foreach (UspVisitEventSelectByVisitGUIDResult result in selectResult)
                                {
                                    Private.VisitEvent visitEvent = (Private.VisitEvent)MethodCaller.CreateInstance(typeof(Private.VisitEvent));

                                    // Common properties inherited from MarketPulseBase<Visit>
                                    LoadProperty(visitEvent, Private.VisitEvent.GUIDProperty, result.VisitEventGUID);
                                    LoadProperty(visitEvent, Private.VisitEvent.InsertDateTimeProperty, result.InsertDateTime.Value);
                                    LoadProperty(visitEvent, Private.VisitEvent.InsertUserGUIDProperty, result.InsertUserGUID.Value);
                                    // Other properties                    
                                    LoadProperty(visitEvent, Private.VisitEvent.VisitGUIDProperty, criteria.Value);
                                    LoadProperty(visitEvent, Private.VisitEvent.VisitEventTypeGUIDProperty, result.VisitEventTypeGUID);

                                    // Mark the Visit Event as a child element
                                    MarkAsChild(visitEvent);

                                    // Make sure that CSLA knows this has changed since being instantiated
                                    MarkOld(visitEvent);

                                    // Add the item to the list
                                    eventList.Add(visitEvent);
                                }
                                eventList.RaiseListChangedEvents = true;

                                // Make sure that CSLA knows this has changed since being instantiated
                                MarkOld(eventList);

                                return eventList;
                            }
                        }
                        catch (InvalidOperationException ioe)
                        {
                            mLog.Error(ioe.ToString());
                            throw ioe;
                        }
                        catch (Exception ex)
                        {
                            mLog.Error(ex.ToString());
                            throw ex;
                        }
                    }

                #endregion

            #endregion

            #region Update Methods

                    /// <summary>
                    /// Method used to persist an altered Visit object in the database.
                    /// </summary>
                    /// <param name="visit">The visit object to persist.</param>
                    /// <returns>The Visit object potentially altered by the act of persisting it.</returns>
                    [Transactional(TransactionalTypes.TransactionScope)]
                    public Private.Visit Update(Private.Visit visit)
                    {
                        using (var manager = ContextManager<MUM_dev>.GetManager(Database.BusinessSystem))
                        {
                            // Set up some local variables to hold the return values from the stored procedure calls
                            Nullable<Guid> userGUID = visit.ActionUserGUID;
                            Nullable<DateTime> dateTime = null;
                            Nullable<Guid> guid = visit.GUID.HasValue ? visit.GUID : null;
                            Nullable<long> versionID = null;

                            // If the object is new (or appears to be new, i.e. a new revision), then Insert a record, 
                            // otherwise Update the current record
                            if (visit.IsNew)
                            {
                                //// Insert the new Visit record
                                //manager.DataContext.UspVisitInsert(ref guid, ref versionID, visit.RoundGUID, visit.UserGUID, visit.BranchGUID, visit.ResponseGUID, visit.SurveyGUID, visit.SurveyVersionID, visit.VisitStatusTypeGUID,
                                //                                visit.ValidStartDateTime, visit.ValidEndDateTime, visit.PlannedDateTime, visit.ActualStartDateTime, visit.ActualEndDateTime, null, userGUID, ref dateTime);

                                //// Load the new values into the Visit object
                                //LoadProperty(visit, BusinessLogic.Private.Visit.GUIDProperty, guid.Value);
                                //LoadProperty(visit, BusinessLogic.Private.Visit.VersionIDProperty, versionID.Value);
                                //LoadProperty(visit, BusinessLogic.Private.Visit.InsertDateTimeProperty, dateTime.Value);
                                //LoadProperty(visit, BusinessLogic.Private.Visit.InsertUserGUIDProperty, userGUID.Value);
                                //LoadProperty(visit, BusinessLogic.Private.Visit.UpdateDateTimeProperty, dateTime.Value);
                                //LoadProperty(visit, BusinessLogic.Private.Visit.UpdateUserGUIDProperty, userGUID.Value);

                            }
                            else if (visit.IsDirty)
                            {
                                // Set default time for anything happening next
                                dateTime = DateTime.Now;

                                // TODO update visit including any changes to visit event type
                                BusinessLogic.Private.Response response = visit.Response;
                                if (response != null)
                                {
                                    if (response.IsNew)
                                    {
                                        // Insert the new Response record
                                        manager.DataContext.UspResponseInsert(ref guid, visit.Survey.GUID, visit.Survey.VersionID, response.ResponseXML, null, userGUID, ref dateTime);

                                        // Load the new values into the Response object
                                        LoadProperty(response, BusinessLogic.Private.Response.GUIDProperty, guid.Value);
                                        LoadProperty(response, BusinessLogic.Private.Response.InsertDateTimeProperty, dateTime.Value);
                                        LoadProperty(response, BusinessLogic.Private.Response.InsertUserGUIDProperty, userGUID.Value);
                                        LoadProperty(response, BusinessLogic.Private.Response.UpdateDateTimeProperty, dateTime.Value);
                                        LoadProperty(response, BusinessLogic.Private.Response.UpdateUserGUIDProperty, userGUID.Value);
                                        // Set the Visit object to know it's set of Responses
                                        LoadProperty(visit, BusinessLogic.Private.Visit.ResponseGUIDProperty, response.GUID);

                                        // Make sure that CSLA knows this has changed since being instantiated
                                        MarkOld(response);
                                    }
                                    else if (response.IsDirty)
                                    {
                                        // Update the existing Response record
                                        manager.DataContext.UspResponseUpdate(response.GUID, visit.SurveyGUID, visit.SurveyVersionID, response.ResponseXML, null, userGUID, ref dateTime);

                                        // Load the updated values into the Response object
                                        LoadProperty(response, BusinessLogic.Private.Response.UpdateDateTimeProperty, dateTime.Value);
                                        LoadProperty(response, BusinessLogic.Private.Response.UpdateUserGUIDProperty, userGUID.Value);

                                        // Make sure that CSLA knows this has changed since being instantiated
                                        MarkOld(response);
                                    }
                                }

                                // Check the rules for this visit before going further.
                                CheckRules(visit);
                                if (visit.BrokenRulesCollection.Count > 0)
                                {
                                    // TODO: JSR: why this?
                                    return visit;
                                }

                                BusinessLogic.Private.VisitEventList events = visit.Events;
                                if (events.IsDirty)
                                {
                                    // TODO find a cleaner way of inserting visits, walking the list doesn't feel right!
                                    // Loop thorought the events list and save dirty one's
                                    foreach (var visitEvent in visit.Events)
                                    {
                                        if (visitEvent.IsNew)
                                        {
                                            // Insert a new Visit Event record
                                            manager.DataContext.UspVisitEventInsert(ref guid, visitEvent.VisitGUID, visitEvent.VisitEventTypeGUID, userGUID, ref dateTime);

                                            // Load the inserted values into the Visit Event object                                    
                                            LoadProperty(visitEvent, BusinessLogic.Private.VisitEvent.GUIDProperty, guid.Value);
                                            LoadProperty(visitEvent, BusinessLogic.Private.VisitEvent.InsertDateTimeProperty, dateTime.Value);
                                            LoadProperty(visitEvent, BusinessLogic.Private.VisitEvent.InsertUserGUIDProperty, userGUID.Value);
                                            LoadProperty(visitEvent, BusinessLogic.Private.VisitEvent.UpdateDateTimeProperty, dateTime.Value);
                                            LoadProperty(visitEvent, BusinessLogic.Private.VisitEvent.UpdateUserGUIDProperty, userGUID.Value);

                                            // Make sure that CSLA thinks this *hasn't* changed since being instantiated
                                            MarkOld(visitEvent);
                                        }
                                    }
                                }

                                // Update the existing Visit record
                                manager.DataContext.UspVisitUpdate(visit.GUID, visit.VersionID, visit.RoundGUID, visit.UserGUID, visit.BranchGUID, visit.ResponseGUID, visit.SurveyGUID, visit.SurveyVersionID, visit.VisitStatusTypeGUID,
                                                                    visit.ValidStartDateTime, visit.ValidEndDateTime, visit.PlannedDateTime, visit.ActualStartDateTime, visit.ActualEndDateTime, null, userGUID, ref dateTime);

                                // Load the updated values into the Visit object
                                LoadProperty(visit, BusinessLogic.Private.Visit.UpdateDateTimeProperty, dateTime.Value);
                                LoadProperty(visit, BusinessLogic.Private.Visit.UpdateUserGUIDProperty, userGUID.Value);

                                // Make sure that CSLA knows this has changed since being instantiated
                                MarkOld(visit);
                            }
                            return visit;
                        }
                    }

            #endregion

        #endregion

    }
}
